function ReplaceTransform()
{
    this.id = null;
    
    this.setId = function( id ){
        this.id = id;
    }
    
    this.loadXML = function ( xml ){
        var eltoId = xml.getElementsByTagName( 'uniqId' )[ 0 ].firstChild.nodeValue;
        var jsCode = xml.getElementsByTagName( 'script' )[ 0 ].firstChild.nodeValue;
        var htmlCode = xml.getElementsByTagName( 'body' )[ 0 ].firstChild.nodeValue;
        
        if( eltoId != null && jsCode != null && htmlCode != null ){
            replaceNode( eltoId, jsCode, htmlCode );
        }
        
        var elto = document.getElementById( this.id );
        
        if( elto!= null ){
            
            if( document.all )
               elto.style.filter = 'alpha(opacity=100)';
            else
                elto.style.opacity = 1;   
        }
    }
    
        
    this.onsend = function(){
        var elto = document.getElementById( this.id );
        
        if( document.all )
           elto.style.filter = 'alpha(opacity=30)';
        else
            elto.style.opacity = 0.3;
    }
    
    this.onerror = function(){
        var elto = document.getElementById( this.id );
        
        if( document.all )
           elto.style.filter = 'alpha(opacity=100)';
        else
            elto.style.opacity = 1;   
    }
}

function AppendTransform()
{
    this.id = null;
    
    this.setId = function( id ){
        this.id = id;
    }
    
    this.loadXML = function ( xml ){
        var eltoId = xml.getElementsByTagName( 'uniqId' )[ 0 ].firstChild.nodeValue;
        var jsCode = xml.getElementsByTagName( 'script' )[ 0 ].firstChild.nodeValue;
        var htmlCode = xml.getElementsByTagName( 'body' )[ 0 ].firstChild.nodeValue;

        //Aqui se tendría que detener el elemnto de carga

        if( eltoId != null && jsCode != null && htmlCode != null ){
            insertAfter( eltoId, jsCode, htmlCode );
        }
    }
    
        
    this.onsend = function(){
        //Esto tendria que activar un elemento de carga
        
    }
    
    this.onerror = function(){
        //Aqui se desactivaría pero para hacer de nuevo la petición
    }
}

function RemoveTransform()
{
    this.id = null;
    
    this.setId = function( id ){
        this.id = id;
    }
    
    this.loadXML = function ( xml ){
        var elto = document.getElementById( this.id );
        elto.parentNode.removeChild( elto );
    }
    
    this.onsend = function(){
        var elto = document.getElementById( this.id );
        
        if( document.all )
           elto.style.filter = 'alpha(opacity=30)';
        else
            elto.style.opacity = 0.3;
    }
    
    this.onerror = function(){
        var elto = document.getElementById( this.id );
        
        if( document.all )
           elto.style.filter = 'alpha(opacity=100)';
        else
            elto.style.opacity = 1;   
    }
}

function replaceNode( id, javascript, html ){
    //el problema del codigo html es que también tiene el Id por lo que sería conveniente eliminar primero el otro
    var elto=document.getElementById(id);
    
    var pater=elto.parentNode;
    var next=elto.nextSibling; //Y si no tiene next

    pater.removeChild(elto);
    
    var parteScript=html.indexOf('<script')==0;
    var partes=html.split(/<\/?script[^>]*>/ig); //esto me lo dejaría dividido por los campos
    
    
    //tengo que extraer las partes script y ejecutarlas por separado con especial cuidado con los document.write()
    //Cambio el document.write('...'); por stdOut+='';
    var stdOut='';
    
    var f=document.write;
    document.write=function(str){
        stdOut+=str;
    }

    eval(javascript);

    for(var i=0;i<partes.length;i++){

        if(parteScript)
            eval(partes[i].replace('<!--', '').replace('-->',''));
        
        else
            stdOut+=partes[i];

        parteScript=!parteScript;
    }


    document.write = f;


    var aux=document.createElement('DIV');
    document.body.appendChild(aux);
    aux.style.display='none';

 
    stdOut = stdOut.replace( new RegExp( "^\\s*" ), "" );


    if(stdOut.toUpperCase().indexOf('<TD')==0){
        aux.innerHTML='<table><tbody><tr>'+stdOut+'</tr></tbody></table>';
    }
    else if(stdOut.toUpperCase().indexOf('<TR')==0){
        aux.innerHTML='<table><tbody>'+stdOut+'</tbody></table>';
    }
    else if(stdOut.toUpperCase().indexOf('<LI')==0){
        aux.innerHTML='<ul>'+stdOut+'</ul>';
    }
    else{
        aux.innerHTML=stdOut;
    }
      
    elto=document.getElementById(id);

    if(next)
        pater.insertBefore(elto, next);
    else
        pater.appendChild(elto);
    
    document.body.removeChild(aux);
}

function insertAfter( id, javascript, html ){
    var elto = document.getElementById( id );
    
    var parteScript = html.indexOf( '<script' ) == 0;
    var partes = html.split( /<\/?script[^>]*>/ig ); //esto me lo dejaría dividido por los campos
    
    //tengo que extraer las partes script y ejecutarlas por separado con especial cuidado con los document.write()
    //Cambio el document.write('...'); por stdOut+='';
    var stdOut='';
    
    var f = document.write;
    document.write = function(str){
        stdOut+=str;
    }

    eval( javascript );

    for(var i=0;i<partes.length;i++){

        if(parteScript)
            eval(partes[i].replace('<!--', '').replace('-->',''));
        
        else
            stdOut+=partes[i];

        parteScript=!parteScript;
    }


    document.write=f;

    while(stdOut.charAt(0)==' ')
        stdOut=stdOut.substring(1);

    if(stdOut.toUpperCase().indexOf('<TR')==0){
        elto.innerHTML += '<tbody>'+stdOut+'</tbody>';
    }
    else
       elto.innerHTML += stdOut;
}


function addEvent(element, eventName, fn) {
    if (element.addEventListener)
        element.addEventListener(eventName, fn, false);
    else if (element.attachEvent)
        element.attachEvent('on' + eventName, fn);
}

xJoakReferer = null;

XMLHttpRequest.prototype.onjoak = function() {
    if (this.status >= 200 && this.status < 400) {

        if( this.responseText != '' ){

            var oDocument = this.responseXML;
// Try parsing responseText
            if ( window.document.all && !window.opera && oDocument && !oDocument.documentElement && this.getResponseHeader( 'Content-Type' ).match(/[^\/]+\/[^\+]+\+xml/)) {

                oDocument	= new window.ActiveXObject( 'Microsoft.XMLDOM' );
                oDocument.loadXML( this.responseText );

                if ( oDocument && ( oDocument.parseError != 0 || ( oDocument.documentElement && oDocument.documentElement.tagName == 'parsererror' )  ) ){
                    if( oDocument.documentElement && oDocument.documentElement.tagName == 'parsererror' ){
                        alert( oDocument.documentElement.childNodes[0].nodeValue );
                    }
                    else{
                        alert(  oDocument.parseError.reason );
                    }

                    this.transform.onerror();
                    return false;
                }
            }

            // Check if there is no error in document
            this.transform.loadXML( oDocument );

        }
        else
            this.transform.loadXML( null );


        joaknize();

    } else {
        this.transform.onerror();
    }
};

function joaknize() {

    if( xJoakReferer == null ) {
        xJoakReferer = window.location.href;
    }
    
    var anchors = document.getElementsByTagName( 'A' );
    
    for ( var i = 0; i < anchors.length; i++ ){
        
        if( !anchors[ i ].joak && anchors[ i ].getAttribute( 'data-joak-href' ) != null ){
            
            var download = anchors[ i ].getAttribute( 'donwload' );
            //Me falta la funcion callback?? No, siempre es la misma, la otra va en  querystring y en el mensaje de vuelta
            
            //tiene que ser 

            if( download == null ) {
                
                anchors[ i ].oldonclick = anchors[ i ].onclick;
                
                anchors[ i ].onclick = function(){

                    if( this.oldonclick != null ) {
                        if( !this.oldonclick() ){
                            return false;
                        }
                    }

                    var transform = this.getAttribute( 'data-joak-transform' );
                    if( transform == null ){
                        transform = 'ReplaceTransform';
                    }

                    var request = new XMLHttpRequest();

                    request.open( 'GET', this.getAttribute( 'data-joak-href' ), true );
                    
                    var accept = this.getAttribute( 'data-joak-accept' );
                    
                    request.setRequestHeader( 'Accept', ( accept != null ) ? accept : 'application/vnd.copperforest.oak+xml' );
                    request.setRequestHeader( 'Oak-Referer', xJoakReferer );

                    eval( 'request.transform = new ' + transform + '()' );

                    request.transform.setId( this.getAttribute( 'data-joak-id' ) );
                    
                    request.onload = request.onjoak;

                    request.onerror = function() {
                        this.transform.onerror();
                    };

                    
                    request.send();
                    request.transform.onsend();
                    
                    return false;
                }
            }
            
            anchors[ i ].joak = true;
        }
        
        //claro, si la llamada es local y no tiene atributo download, entoces si puedo hacer uso
        
        
        //va er si son llamadas al mismo dominio de la página y si tienen un mime de texto... no siempre, pq a veces quiero descargarlos
        //Aqui debería tener todos los 
    }

    var forms = document.getElementsByTagName( 'FORM' );

    for (var i = 0; i < forms.length; i++){
        
        
        //en caso del enctype puedo hacer un formulario a parte que me devuelva la ruta del fichero en el servidor
        if ( (forms[ i ].joak == null || !forms[ i ].joak ) && forms[ i ].getAttribute( 'data-joak-href' ) != null) {
            /*
            var enctype = forms[i].getAttribute("enctype").toLowerCase();
            
            if ( enctype != null && enctype == 'multipart/form-data' ){
                for ( j = 0; j < this.elements.length; j++ ){
                    
                    if ( forms[ i ].elements[ j ].getAttribute( 'type' ) == 'file' ) {
                        forms[ i ].elements[ j ].addEventListener
                    }
                    //else if ( this.elements[j].name == 'Callback' ) La funcion de callback va como está como el id?

                    
                }
                //Aqui tengo que comprobar si hay archivos de tipo file
            }
            
            forms[i].setAttribute('enctype','application/x-www-form-urlencoded');
            */
           
            //tengo que cambiar el método submit de los fomularios. Mi nuevo método también tiene que llamar a los onsubmits
            //igualmente tendrá que llamar pero por ajax al action del submit utilizando el 
            //tengo que utilizar el atributo action, method, accept-charset, enctype y con cual indico el Accept.
            //En teoría debería ponerlo automaticamente oak. si está en el root o no
            if( forms[i].onsubmit ){
                forms[i].oldonsubmit = forms[i].onsubmit;
            }
            
            forms[i].onsubmit = function(){
                if( this.oldonsubmit != null ) {
                    if( !this.oldonsubmit() ){
                        return false;
                    }
                }
                    
                var valores = new Array();
                var j = 0;

                for (i = 0; i < this.elements.length; i++) {
                    var nombre = encodeURIComponent(this.elements[i].name);

                    switch (this.elements[i].type) {

                        case 'select':
                            if ( isNaN( this.elements[i].selectedIndex ) ) {
                                for ( j = 0; j < this.elements[i].options.length; j++ )
                                    if (this.elements[i].options[j].selected)
                                        valores[valores.length] = nombre + '=' + encodeURIComponent(this.elements[i].options[j].value);
                            }
                            else if (this.elements[i].selectedIndex > -1)
                                valores[valores.length] = nombre + '=' + encodeURIComponent(this.elements[i].options[this.elements[i].selectedIndex].value);
                            break;

                        case 'select-one':
                            if (this.elements[i].selectedIndex > -1)
                                valores[valores.length] = nombre + '=' + encodeURIComponent(this.elements[i].options[this.elements[i].selectedIndex].value);
                            break;

                        case 'select-multiple':
                            for (j = 0; j < this.elements[i].options.length; j++)
                                if (this.elements[i].options[j].selected)
                                    valores[valores.length] = nombre + '=' + encodeURIComponent(this.elements[i].options[j].value);
                            break;

                        case 'radio':
                        case 'checkbox':
                            if (this.elements[i].length) {
                                for (j = 0; j < this.elements[i].length; j++)
                                    if (this.elements[i][j].checked)
                                        valores[valores.length] = nombre + '=' + encodeURIComponent(this.elements[i][j].value);
                            }
                            else if (this.elements[i].checked)
                                valores[valores.length] = nombre + '=' + encodeURIComponent(this.elements[i].value)
                            break;

                        case 'text':
                        case 'textarea':
                        case 'password':
                        case 'hidden':
                            valores[valores.length] = nombre + '=' + encodeURIComponent(this.elements[i].value)
                            break;

                            //TENGO QUE AÑADIR EL CASO FILE QUE TEndría que ponerle un evento on change, pero no aqui, sino fuera del onsubmit
                    }
                }

                var transform = this.getAttribute( 'data-joak-transform' );
                if( transform == null ){
                    transform = 'ReplaceTransform';
                }

                var request = new XMLHttpRequest();
                var isGet = this.getAttribute( 'method' ).toUpperCase() == 'GET';

                request.open( this.getAttribute( 'method' ).toUpperCase(), this.getAttribute( 'data-joak-href' ) + ( isGet ? valores.join('&') : '' ), true );

                var accept = this.getAttribute( 'data-joak-accept' );
                request.setRequestHeader( 'Accept', ( accept != null ) ? accept : 'application/vnd.copperforest.oak+xml' );
                request.setRequestHeader( 'Referer', xJoakReferer );

                eval( 'request.transform = new ' + transform + '()' );

                request.transform.setId( this.getAttribute( 'data-joak-id' ) );

                request.onload = request.onjoak;

                request.onerror = function() {
                    this.transform.onerror();
                };

                if( isGet ){
                    request.send();
                }
                else{
                    request.setRequestHeader( 'Content-Type',
                                'application/x-www-form-urlencoded' );

                    request.send( valores.join( '&' ) );
                }

                request.transform.onsend();

                return false;
            }
            
            forms[ i ].joak = true;
        }

    }
}

addEvent( window, 'load', joaknize );